/*
 * File:    ShutdownHook.java
 * Created: 22-Nov-2007
 * 
 * by Kenji Hollis <kenji@bitgatesoftware.com>
 * Released under the Creative Commons License version 2.5
 */

package com.bitgate.util.shutdown;

import java.lang.reflect.Method;
import java.util.ArrayList;

public class ShutdownHook {
	
	protected final ArrayList<ShutdownHookInterface> shutdownList = new ArrayList<ShutdownHookInterface>();
	protected final ArrayList<Class<?>> shutdownClassList = new ArrayList<Class<?>>();
	private static final ShutdownHook _default = new ShutdownHook();
	
	private ShutdownHook() {
		Runtime.getRuntime().addShutdownHook(new Thread() {
			@Override
			public void run() {
				System.err.println("--- Terminating system processes.");
				
				for(ShutdownHookInterface shInterface : ShutdownHook.this.shutdownList) {
					shInterface.shutdown();
				}
				
				for(Class<?> shutdownClass : ShutdownHook.this.shutdownClassList) {
					Method shutdownMethod = null;
					
					try {
						shutdownMethod = shutdownClass.getMethod("shutdown", new Class[] { });
					} catch(Exception e) {
						System.err.println("--- Shutdown method in class '" + shutdownClass.getName() + "' failed: " + 
								e.getMessage());
						continue;
					}
					
					if (shutdownMethod != null) {
						try {
							shutdownMethod.invoke(shutdownClass.newInstance());
						} catch(Exception e) {
							System.err.println("--- Shutdown method in class '" + shutdownClass.getName() + "' failed: " +
									e.getMessage());
							continue;
						}
					}
				}
				
				try {
					System.err.println("--- Waiting 5 seconds for normal termination.");
					
					synchronized(this) {
						wait(5000);
					}
				} catch(Exception e) {
					System.err.println("--- Abnormal program termination: " + e.getMessage());
					e.printStackTrace();
					return;
				}
				
				boolean notDone = false;
				
				for(ShutdownHookInterface shInterface : shutdownList) {
					if (!shInterface.isShutdown()) {
						System.err.println("--- One or more threads indicate not shut down.  This may lead to abnormal " +
								"termination of this server.");
						notDone = true;
					}
				}
				
				if (!notDone) {
					System.err.println("--- Normal system shutdown.");
				} else {
					System.err.println("--- Normal system shutdown with possible abnormal/out-of-sync thread termination.");
				}
				
				return;
			}
		});
	}
	
	public static final ShutdownHook getInstance() {
		return _default;
	}
	
	public void register(ShutdownHookInterface shInterface) {
		shutdownList.add(shInterface);
	}
	
	public void register(Class<?> shClass) {
		Class<?> interfaces[] = shClass.getInterfaces();
		
		for(Class<?> iFace : interfaces) {
			if (iFace.getName().contains("ShutdownHookInterface")) {
				shutdownClassList.add(shClass);
				return;
			}
		}
		
		System.err.println("--- Unable to add class '" + shClass.getName() + "': no interface for ShutdownHookInterface " +
				"implemented.");
	}
	
}